#include <iostream>
#include <cstring>
#include <sstream>
#include <fstream>
#include <algorithm>
#include <UserManager.h>
#include <commands.h>
#include <modules.h>
#include <framework.h>
#include <cnotify.h>
#include <log.h>
#include <UserInfo.h>
#include <keyMap.h>
#include <nlohmann/json.hpp>
#define DEFAULT_USER_FILE "userinfo.json"

// -------------------------- SHA-256 Core Implementation --------------------------
// SHA-256 initial hash values (H0-H7)
static const uint32_t kSHA256_H[] = {
    0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
    0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};

// SHA-256 round constants (K0-K63)
static const uint32_t kSHA256_K[] = {
    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};

// 32-bit right circular shift
static inline uint32_t rotr(uint32_t x, uint32_t n)
{
    return (x >> n) | (x << (32 - n));
}

// Process single 512-bit block (SHA-256 compression logic)
static void sha256_compress(uint32_t state[8], const uint8_t block[64])
{
    uint32_t w[64], a, b, c, d, e, f, g, h, t1, t2;

    // Expand 64-byte block to 64 32-bit words (W[0]-W[15])
    for (int i = 0; i < 16; ++i)
        w[i] = (block[i * 4] << 24) | (block[i * 4 + 1] << 16) | (block[i * 4 + 2] << 8) | block[i * 4 + 3];

    // Expand W[16]-W[63]
    for (int i = 16; i < 64; ++i)
    {
        uint32_t s0 = rotr(w[i - 15], 7) ^ rotr(w[i - 15], 18) ^ (w[i - 15] >> 3);
        uint32_t s1 = rotr(w[i - 2], 17) ^ rotr(w[i - 2], 19) ^ (w[i - 2] >> 10);
        w[i] = (w[i - 16] + s0 + w[i - 7] + s1) & 0xFFFFFFFF;
    }

    // Init working variables with current state
    a = state[0], b = state[1], c = state[2], d = state[3];
    e = state[4], f = state[5], g = state[6], h = state[7];

    // 64 rounds of compression
    for (int i = 0; i < 64; ++i)
    {
        uint32_t S1 = rotr(e, 14) ^ rotr(e, 18) ^ rotr(e, 41);
        uint32_t ch = (e & f) ^ (~e & g);
        t1 = h + S1 + ch + kSHA256_K[i] + w[i];
        uint32_t S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
        uint32_t maj = (a & b) ^ (a & c) ^ (b & c);
        t2 = S0 + maj;

        h = g;
        g = f;
        f = e;
        e = (d + t1) & 0xFFFFFFFF;
        d = c;
        c = b;
        b = a;
        a = (t1 + t2) & 0xFFFFFFFF;
    }

    // Update state with compression result
    state[0] += a;
    state[1] += b;
    state[2] += c;
    state[3] += d;
    state[4] += e;
    state[5] += f;
    state[6] += g;
    state[7] += h;
    // Keep 32-bit range
    for (int i = 0; i < 8; ++i)
        state[i] &= 0xFFFFFFFF;
}

// SHA-256 hash function: input string -> 64-char hex output
std::string UserManager::sha256(const std::string &input)
{
    uint32_t state[8];
    std::memcpy(state, kSHA256_H, sizeof(kSHA256_H)); // Init state
    size_t input_len = input.size(), total_len = input_len;
    uint8_t block[64] = {0};

    // Process full 64-byte blocks
    size_t i = 0;
    while (total_len >= 64)
    {
        std::memcpy(block, input.data() + i, 64);
        sha256_compress(state, block);
        i += 64;
        total_len -= 64;
    }

    // Pad remaining data: add 0x80 + zeros
    std::memcpy(block, input.data() + i, total_len);
    block[total_len] = 0x80;
    uint8_t *ptr = block + total_len + 1;

    // Pad with extra block if needed (insufficient space for length)
    if (64 - total_len - 1 < 8)
    {
        std::memset(ptr, 0, 64 - total_len - 1);
        sha256_compress(state, block);
        std::memset(block, 0, 64);
        ptr = block;
    }
    else
    {
        std::memset(ptr, 0, 64 - total_len - 1 - 8);
    }

    // Append input length (bits, big-endian)
    uint64_t bit_len = (uint64_t)input_len * 8;
    for (int j = 0; j < 8; ++j)
        block[64 - 8 + j] = (bit_len >> (8 * (7 - j))) & 0xFF;
    sha256_compress(state, block);

    // Convert state to 64-char hex string
    char hex_str[65] = {0};
    for (int j = 0; j < 8; ++j)
        sprintf(hex_str + j * 8, "%08x", state[j]);
    return std::string(hex_str);
}

// -------------------------- JSON Processing (Error Log Only, No Exceptions) --------------------------
LOCAL void to_json(nlohmann::json &j, const UserInfo &user)
{
    j =
    {
            {"username", user.username},
            {"password", user.password},
            {"permission", static_cast<int>(user.permission)}
    };
}

LOCAL void from_json(const nlohmann::json &j, UserInfo &user)
{
    // Initialize fields to avoid dirty data
    user.username.clear();
    user.password.clear();
    user.permission = UserPermission::BANNED;

    if (j.contains("username") && j["username"].is_string())
    {
        j["username"].get_to(user.username);
    }
    else
    {
        LOG_ERROR("JSON parse error: missing valid 'username' field");
        return;
    }

    if (j.contains("password") && j["password"].is_string())
    {
        j["password"].get_to(user.password);
    }
    else
    {
        LOG_ERROR("JSON parse error: missing valid 'password' field (user: %s)", user.username.c_str());
        return;
    }

    if (j.contains("permission") && j["permission"].is_number_integer())
    {
        user.permission = static_cast<UserPermission>(j["permission"].get<int>());
    }
    else
    {
        LOG_ERROR("JSON parse error: missing valid 'permission' field (must be integer) (user: %s)", user.username.c_str());
        user.permission = UserPermission::BANNED;
        return;
    }
}

LOCAL bool validate_user(UserInfo &user)
{
    if (user.username.empty())
    {
        LOG_ERROR("User validation failed: username is empty");
        return false;
    }

    if (user.password.empty())
    {
        LOG_ERROR("User validation failed: password hash is empty (user: %s)", user.username.c_str());
        return false;
    }
    if (user.password.size() != 64)
    {
        LOG_ERROR("User validation failed: password hash length invalid (must be 64 chars) (user: %s, length: %zu)",
                  user.username.c_str(), user.password.size());
        return false;
    }
    for (char c : user.password)
    {
        if (!isxdigit(static_cast<unsigned char>(c)))
        {
            LOG_ERROR("User validation failed: password hash contains non-hex character '%c' (user: %s)",
                      c, user.username.c_str());
            return false;
        }
    }

    int isLegalPerm = user.permission & 
            (UserPermission::BANNED|
            UserPermission::GUEST|
            UserPermission::OPERATOR|
            UserPermission::ADMIN|
            UserPermission::SUPER_ADMIN);

    if (isLegalPerm == UserPermission::BANNED)
    {
        LOG_WARN("User validation warning: invalid permission value %d, set to BANNED (user: %s)",
                 static_cast<int>(user.permission), user.username.c_str());
        user.permission = UserPermission::BANNED;
    }

    return true;
}

LOCAL bool readUserInfoConfig(const std::string &filename, UserInfoMap &users)
{
    std::ifstream ifs(filename);
    if (!ifs)
    {
        LOG_ERROR("Cannot read %s", filename.c_str());
        return false;
    }
    nlohmann::json j;
    ifs >> j;

    users = j.get<UserInfoMap>();

    for (auto it = users.begin(); it != users.end();)
    {
        auto &[username, user] = *it;
        if (!validate_user(it->second))
        {
            LOG_WARN("Read user config: skip invalid user [%s]", username.empty() ? "unknown" : username.c_str());
            users.erase(it++);
        }
        else
        {
            ++it;
        }
    }

    LOG_INFO("Read user config success: loaded %zu valid users from %s", users.size(), filename.c_str());
    return true;
}

LOCAL bool writeUserInfoConfig(const std::string &filename, const UserInfoMap &users)
{
    try
    {
        std::ofstream ofs(filename);
        if (!ofs)
        {
            LOG_ERROR("Cannot write to %s", filename.c_str());
            return false;
        }
        ofs << nlohmann::json(users).dump(4);
        return true;
    }
    catch (const std::exception &e)
    {
        LOG_ERROR("Write failed: %s", e.what());
        return false;
    }
}

STATUS UserManager::initBuiltinUsers()
{
    return addUser(
        UserConstants::DEFAULT_SUPER_ADMIN_USERNAME,
        UserConstants::DEFAULT_SUPER_ADMIN_PASSWORD,
        UserConstants::DEFAULT_SUPER_ADMIN_PERMISSION
    );
}

STATUS UserManager::saveUserConfig()
{
    if (!writeUserInfoConfig(utils::format("%s/%s", DEFAULT_CONFIG_PATH, DEFAULT_USER_FILE).c_str(), m_users))
    {
        LOG_ERROR("Saving userinfo config fail");
        return RET_ERROR;
    }
    return OK;
}

UserPermission UserManager::verifyUser(const std::string &username, const std::string &password)
{
    std::lock_guard<std::mutex> lock(m_userMutex);
    auto it = m_users.find(username);
    if (it == m_users.end())
    {
        return UserPermission::BANNED;
    }

    if (it->second.password == sha256(password))
    {
        return it->second.permission;
    }
    return UserPermission::BANNED;
}

STATUS UserManager::addUser(const std::string &username, const std::string &password, UserPermission permission)
{
    COND_CHECK_RET_ERROR(username.empty() || password.empty());

    std::lock_guard<std::mutex> lock(m_userMutex);
    COND_CHECK_RET_ERROR(m_users.count(username) > 0);
    m_users[username] = {username, sha256(password), permission};
    LOG_INFO("Added user %s for permission %d", username.c_str(), permission);
    return saveUserConfig();
}

STATUS UserManager::deleteUser(const std::string &username)
{
    std::lock_guard<std::mutex> lock(m_userMutex);
    auto iter = m_users.find(username);
    COND_CHECK_RET_ERROR(iter == m_users.end());
    m_users.erase(iter);
    return saveUserConfig();
}

STATUS UserManager::dump(TextTable &t)
{
    t.setTableName("UserInfo");
    t.addHeader("username");
    t.addHeader("permission").endOfRow();
    std::lock_guard<std::mutex> lock(m_userMutex);
    for (auto& iter : m_users)
    {
        t.add(iter.second.username);
        t.add(std::string(userPermission_to_string(iter.second.permission))).endOfRow();
    }
    return OK;
}
PROCESS_IMPL_DESC(UserManager, process)
{
    PROCESS_BEGIN()
    PROCESS_CALL(CMD_SYS_SHUTDOWN, sysShutdown)
    PROCESS_END(RET_ERROR)
}

PROCESS_IMPL_DESC(UserManager, sysShutdown)
{
    return destory();
}

STATUS UserManager::preInit()
{
    utils::mkdirPath(DEFAULT_CONFIG_PATH);
    readUserInfoConfig(utils::format("%s/%s", DEFAULT_CONFIG_PATH, DEFAULT_USER_FILE), m_users);
    initBuiltinUsers();
    return OK;
}

STATUS UserManager::postInit()
{
    COND_CHECK_RET_ERROR(registerMessageListener(MODULE_USER_MGR) != OK);

    return OK;
}
STATUS UserManager::destory()
{

    return saveUserConfig();
}
REG_TO_FRAMEWORK(UserManager, MODULE_USER_MGR)